package tms.business.time;

import tms.model.login.UserEntity;
import tms.model.time.TimeEntity;
import tms.persistence.time.TimeProvider;
import tms.util.activity.UserActivityManager;
import tms.util.helper.DateHelper;

import javax.ejb.EJB;
import javax.ejb.Local;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.*;


@Named
@Local
@Stateless
public class TimeService {
    @EJB
    private TimeProvider timeProvider;
    @Inject
    UserActivityManager userActivityManager;


    public List<TimeEntity> getCurrentWeekTimes(Date today, Integer userId, Locale locale) {
        List<Date> week = getCurrentWeek(today, locale);
        List<TimeEntity> retVal = timeProvider.getTimesForPeriod(DateHelper.getDayBegin(week.get(0)) , DateHelper.getDayEnd(week.get(week.size() - 1)), userId);
        return buildCompleteWeek(retVal, today, locale);
    }

    public List<Date> getCurrentWeek(Date today, Locale locale) {
        List<Date> retVal = new ArrayList<Date>();

        Calendar calendar = Calendar.getInstance(locale);
        calendar.setTime(today);
        while (calendar.get(Calendar.DAY_OF_WEEK) != calendar.getFirstDayOfWeek()) {
            calendar.add(Calendar.DAY_OF_MONTH, -1);
        }
        for (int i = 0; i < 7; i++) {
            retVal.add(calendar.getTime());
            calendar.add(Calendar.DAY_OF_MONTH, 1);            
        }

        return retVal;
    }

    public TimeEntity getCurrentTime(Integer userId, Date today) {
        TimeEntity retVal = null;
        List<TimeEntity> timeEntities = timeProvider.getTimesForPeriod(DateHelper.getDayBegin(today), DateHelper.getDayEnd(today), userId);
        if (!timeEntities.isEmpty()) {
            retVal = timeEntities.get(0);
        }

        return retVal;
    }

    public void startTime(Integer userId, Date today) {
        List<TimeEntity> timeEntities = timeProvider.getTimesForPeriod(DateHelper.getDayBegin(today), DateHelper.getDayEnd(today), userId);
        // check whether user already start time today
        if (timeEntities.size() == 0) {
            // stop all running times for user
            timeProvider.stopRunningTimes(DateHelper.getDayBegin(today), userId);

            // create new time
            TimeEntity timeEntity = new TimeEntity();
            timeEntity.setUserId(userId);
            timeEntity.setRunning(true);
            timeEntity.setStartTime(today);
            timeProvider.createTime(timeEntity);
        } else {
            TimeEntity timeEntity = timeEntities.get(0);
            // if current time entity is stopped then start it
            if (timeEntity.getStopTime() != null) {
                timeEntity.setStopTime(null);
                timeEntity.setRunning(true);
                timeProvider.updateTime(timeEntity);
            }
        }
    }

    public void pauseTime(Integer userId) {
        timeProvider.pauseTime(userId);
    }

    public void playTime(Integer userId, Date today) {
        List<TimeEntity> timeEntities = timeProvider.getTimesForPeriod(DateHelper.getDayBegin(today), DateHelper.getDayEnd(today), userId);
        if (timeEntities.size() != 0) {
            TimeEntity timeEntity = timeEntities.get(0);
            timeEntity.setRunning(true);
            timeEntity.setStopTime(null);
            timeProvider.updateTime(timeEntity);    
        }
    }

    public void stopTime(Integer userId, Date today) {
        List<TimeEntity> timeEntities = timeProvider.getTimesForPeriod(DateHelper.getDayBegin(today), DateHelper.getDayEnd(today), userId);
        if (timeEntities.size() != 0) {
            TimeEntity timeEntity = timeEntities.get(0);
            timeEntity.setRunning(false);
            timeEntity.setStopTime(today);
            timeProvider.updateTime(timeEntity);
        }
    }

    public Boolean isCurrentTime(TimeEntity timeEntity, Date today) {
        boolean retVal = false;
        if (timeEntity != null && timeEntity.getStartTime() != null) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(timeEntity.getStartTime());
            int startDay = calendar.get(Calendar.DAY_OF_MONTH);
            int startMonth = calendar.get(Calendar.MONTH);
            int startYear = calendar.get(Calendar.YEAR);
            calendar.setTime(today);
            int todayDay = calendar.get(Calendar.DAY_OF_MONTH);
            int currentMonth = calendar.get(Calendar.MONTH);
            int currentYear = calendar.get(Calendar.YEAR);

            if (startDay == todayDay && startMonth == currentMonth && startYear ==currentYear) {
                retVal = true;
            }
        }
        return retVal;
    }

    public TimeEntity updateTime(TimeEntity timeEntity) {
        return timeProvider.updateTime(timeEntity);
    }

    public boolean hasPreviousWeek(Integer userId, Date today, Locale locale) {
        boolean retVal = false;
        List<Date> currentWeek = getCurrentWeek(today, locale);
        Long number = timeProvider.getTimesNumberBeforeDate(userId, DateHelper.getDayBegin(currentWeek.get(0)));
        if (number != null && number > 0) {
            retVal = true;
        }
        return retVal;
    }

    public boolean hasNextWeek(Integer userId, Date today, Locale locale) {
        boolean retVal = false;
        List<Date> currentWeek = getCurrentWeek(today, locale);
        Long number = timeProvider.getTimesNumberAfterDate(userId, DateHelper.getDayEnd(currentWeek.get(currentWeek.size() - 1)));
        if (number != null && number > 0) {
            retVal = true;
        }
        return retVal;
    }

    public Date getLastStartDate(Integer userId) {
        return timeProvider.getLastStartDate(userId);
    }

    public void updateNotifiedFlagForUsers(List<UserEntity> users) {
        Date today = new Date();
        Date todayBegin = DateHelper.getDayBegin(today);
        Date todayEnd = DateHelper.getDayEnd(today);
        for (UserEntity user : users) {
            List<TimeEntity> times = timeProvider.getTimesForPeriod(todayBegin, todayEnd, user.getId());
            if (!times.isEmpty()) {
                TimeEntity timeEntity = times.get(0);
                timeEntity.setUserNotified(true);
                timeProvider.updateTime(timeEntity);
            }
        }
    }

    public void autostopTimes() {
        Date now = new Date();

        List<UserEntity> users = timeProvider.getUsersWithWorkDayEnded(new Date());        
        for (UserEntity user : users) {
            Date lastActiveDate = userActivityManager.getLastActivityDate(user.getId());
            if (lastActiveDate != null) {
                long sinceLastActivity = now.getTime() - lastActiveDate.getTime();
                if (user.getProfile().getAutostop() && sinceLastActivity >= user.getProfile().getAutostopTime()) {
                    timeProvider.stopRunningTimes(now, user.getId());
                }
            } else if (user.getProfile().getAutostop()) {
                timeProvider.stopRunningTimes(now, user.getId());
            }
        }
    }


    private List<TimeEntity> buildCompleteWeek(List<TimeEntity> week, Date today, Locale locale) {
        List<TimeEntity> retVal = new ArrayList<TimeEntity>();

        if (week.size() != 0) {
            Iterator<TimeEntity> iterator = week.iterator();
            TimeEntity timeEntity = iterator.next();

            Calendar calendarForTimes = Calendar.getInstance(locale);
            Calendar calendarForDates = Calendar.getInstance(locale);

            for (Date date : getCurrentWeek(today, locale)) {
                calendarForTimes.setTime(timeEntity.getStartTime());
                calendarForDates.setTime(date);
                if (calendarForTimes.get(Calendar.DAY_OF_WEEK) == calendarForDates.get(Calendar.DAY_OF_WEEK)) {
                    retVal.add(timeEntity);
                    if (iterator.hasNext()) {
                        timeEntity = iterator.next();
                    }
                } else {
                    retVal.add(new TimeEntity(-calendarForDates.get(Calendar.DAY_OF_WEEK)));
                }
            }
        } else {
            for (int i = 0; i < 7; i++) {
                retVal.add(i, new TimeEntity(-i));
            }
        }

        return retVal;
    }
}
